/**
 * Created by Forcs on 16/4/10.
 */
var model = require('../db/Model');
var Flavors = require('./Flavors');
var Products = require('./Products');
var mongoose = require('mongoose');
var moment = require('moment');
var utils = require('../utils/Utils');
var redis = require('redis');
var co = require('co');

var Manager = function () {

  var self = this;
  self._cached = undefined;

  self._initDefaultData = function () {
    return {
      news: 0,
      visited: 0,
      users: 0,
      durations: 0,
      playCount: 0
    }
  };

  self._initDataItem = function (date, biz, flavors, products) {
    var defData = self._initDefaultData();

    var __create = function (item, defData, flavors) {
      return {
        id: item.code,
        name: item.name,
        data: defData,
        flavors: flavors
      }
    };

    var productDocs = [];
    var categoryDocs = [];
    var contentDocs = [];
    var flavorDocs = [];
    flavors.forEach(function (flavor) {
      if (flavor.biz === biz) {
        flavorDocs.push(flavor);
      }
    });
    products.forEach(function (product) {
      if (product.biz !== biz) {
        return;
      }

      productDocs.push(__create(product, defData, flavors));
      var productId = product.code;

      if (product.categories && product.categories.length) {
        product.categories.forEach(function (category) {
          var cateItem = __create(category, defData, flavors);
          cateItem.product = productId;
          categoryDocs.push(cateItem);
          var categoryId = category.code;
          if (category.contents && category.contents.length) {
            category.contents.forEach(function (content) {
              var contItem = __create(content, defData, flavors);
              contItem.product = productId;
              contItem.category = categoryId;
              contentDocs.push(contItem);
            });
          }
        });
      }
    });

    return {
      date: date,
      biz: biz,
      data: defData,
      flavors: flavorDocs,
      products: productDocs,
      categories: categoryDocs,
      contents: contentDocs
    };
  };

  self._getTodayDoc = function (date, biz) {
    return new Promise(function (resolve, reject) {
      co(function * () {
        if (self._cached === undefined) {
          self._cached = yield self.$model.findOne({ date: date, biz: biz }).exec();
          if (!self._cached) {
            self._cached = yield new self.$model(
              self._initDataItem(
                date,
                biz,
                yield Flavors.$manager.allWithBiz(biz,
                  {
                    converter: function (item) {
                      return {
                        id: item.id,
                        name: item.name,
                        biz: biz,
                        data: self._initDefaultData()
                      }
                    }
                  }
                ),
                yield Products.$manager.allWithBiz(biz)
              )
            ).save();
          }
        } else if (self._cached.date !== date) {
          self._cached = yield new self.$model(
            self._initDataItem(
              date,
              biz,
              yield Flavors.$manager.allWithBiz(biz,
                {
                  converter: function (item) {
                    return {
                      id: item.id,
                      name: item.name,
                      biz: biz,
                      data: self._initDefaultData()
                    }
                  }
                }
              ),
              yield Products.$manager.allWithBiz(biz)
            )
          ).save();
        }
        resolve(self._cached);
      }).catch(function (err) {
        reject(err);
      });
    });
  }
};

Manager.prototype.incrementVisitedByProduct = function (date, biz, product, isNewUser, flavor, func) {
  var self = this;
  return new Promise(function (resolve, reject) {
    co(function * () {
      var todayDay = yield self._getTodayDoc(date, biz);

      todayDay.data.incrementVisited(isNewUser);

      var pi = todayDay.products.length || 0;
      while (pi--) {
        var prod = todayDay.products[pi];
        if (prod.id === product) {
          prod.data.incrementVisited(isNewUser);

          var pfi = prod.flavors.length || 0;
          while (pfi--) {
            var pf = prod.flavors[pfi];
            if (pf.id === flavor) {
              pf.data.incrementVisited(isNewUser);
              break;
            }
          }
          break;
        }
      }

      var fi = todayDay.flavors.length || 0;
      while (fi--) {
        var tf = todayDay.flavors[fi];
        if (tf.id === flavor) {
          tf.data.incrementVisited(isNewUser);
        }
      }

      var result = yield todayDay.save();
      result.product = product;
      result.flavor = flavor;
      result.isNewUser = isNewUser;
      self.notify('inc.product.visited', result);
      if (utils.isFunction(func)) {
        func.call(this, undefined, result);
      }
      resolve(result);
    }).catch(function (err) {
      if (utils.isFunction(func)) {
        func.call(this, err);
      }
      reject(err)
    })
  });
};

Manager.prototype.incrementVisitedByContent = function (date, biz, product, category, content, isNewUser, flavor, func) {
  var self = this;
  return new Promise(function (resolve, reject) {
    co(function * () {
      var todayDay = yield self._getTodayDoc(date, biz);

      todayDay.data.incrementPlayCount();

      var pi = todayDay.products.length || 0;
      while (pi--) {
        var prod = todayDay.products[pi];
        if (prod.id === product) {
          prod.data.incrementPlayCount();

          var pfi = prod.flavors.length || 0;
          while (pfi--) {
            var pf = prod.flavors[pfi];
            if (pf.id === flavor) {
              pf.data.incrementPlayCount();
              break;
            }
          }
          break;
        }
      }

      var fi = todayDay.flavors.length || 0;
      while (fi--) {
        var tf = todayDay.flavors[fi];
        if (tf.id === flavor) {
          tf.data.incrementPlayCount();
        }
      }

      var cai = todayDay.categories.length || 0;
      while (cai--) {
        var cate = todayDay.categories[cai];
        if (cate.product === product && cate.id === category) {
          cate.data.incrementVisited(isNewUser)
            .incrementPlayCount();

          var cafi = cate.flavors.length || 0;
          while (cafi--) {
            var caf = cate.flavors[cafi];
            if (caf.id === flavor) {
              caf.data.incrementVisited(isNewUser)
                .incrementPlayCount();
              break;
            }
          }
          break;
        }
      }

      var coi = todayDay.contents.length || 0;
      while (coi--) {
        var cont = todayDay.contents[coi];
        if (cont.product === product && cont.category === category && cont.id === content) {
          cont.data.incrementVisited(isNewUser)
            .incrementPlayCount();

          var cofi = cont.flavors.length || 0;
          while (cofi--) {
            var cof = cont.flavors[cofi];
            if (cof.id === flavor) {
              cof.data.incrementVisited(isNewUser)
                .incrementPlayCount();
              break;
            }
          }
          break;
        }
      }

      var result = yield todayDay.save();
      result.product = product;
      result.category = category;
      result.content = content;
      result.isNewUser = isNewUser;
      result.flavor = flavor;
      self.notify('inc.content.visited', result);
      if (utils.isFunction(func)) {
        func.call(this, undefined, result);
      }
      resolve(result);
    }).catch(function (err) {
      if (utils.isFunction(func)) {
        func.call(this, err);
      }
      reject(err)
    })
  });
};

Manager.prototype.incrementDurationByContent = function (date, biz, product, category, content, flavor, duration, func) {
  var self = this;
  return new Promise(function (resolve, reject) {
    co(function * () {
      var todayDay = yield self._getTodayDoc(date, biz);
      
      todayDay.data.incrementDuration(duration);

      var pi = todayDay.products.length || 0;
      while (pi--) {
        var prod = todayDay.products[pi];
        if (prod.id === product) {
          prod.data.incrementDuration(duration);

          var pfi = prod.flavors.length || 0;
          while (pfi--) {
            var pf = prod.flavors[pfi];
            if (pf.id === flavor) {
              pf.data.incrementDuration(duration);
              break;
            }
          }
          break;
        }
      }

      var fi = todayDay.flavors.length || 0;
      while (fi--) {
        var tf = todayDay.flavors[fi];
        if (tf.id === flavor) {
          tf.data.incrementDuration(duration);
        }
      }

      var cai = todayDay.categories.length || 0;
      while (cai--) {
        var cate = todayDay.categories[cai];
        if (cate.product === product && cate.id === category) {
          cate.data.incrementDuration(duration);

          var cafi = cate.flavors.length || 0;
          while (cafi--) {
            var caf = cate.flavors[cafi];
            if (caf.id === flavor) {
              caf.data.incrementDuration(duration);
              break;
            }
          }
          break;
        }
      }

      var coi = todayDay.contents.length || 0;
      while (coi--) {
        var cont = todayDay.contents[coi];
        if (cont.product === product && cont.category === category && cont.id === content) {
          cont.data.incrementDuration(duration);

          var cofi = cont.flavors.length || 0;
          while (cofi--) {
            var cof = cont.flavors[cofi];
            if (cof.id === flavor) {
              cof.data.incrementDuration(duration);
              break;
            }
          }
          break;
        }
      }

      var result = yield todayDay.save();
      result.product = product;
      result.category = category;
      result.content = content;
      result.duration = duration;
      result.flavor = flavor;
      self.notify('inc.content.duration', result);
      if (utils.isFunction(func)) {
        func.call(this, undefined, result);
      }
      resolve(result);
    }).catch(function (err) {
      if (utils.isFunction(func)) {
        func.call(this, err);
      }
      reject(err)
    })
  });
};

var dataSchema = new mongoose.Schema({
  news: Number,
  visited: Number,
  users: Number,
  durations: Number,
  playCount: Number
});

dataSchema.methods.incrementDuration = function (inc) {
  if (inc) {
    this.durations += parseInt(inc);
  }
  return this;
};

dataSchema.methods.incrementVisited = function () {
  var inc = 1;
  if (arguments.length) {
    var isNew = !!arguments[0];
    if (arguments.length > 1) {
      inc = parseInt(arguments[1]);
    }
    if (isNew) {
      this.news += inc;
      this.users += inc;
    }
  }
  this.visited += inc;
  return this;
};

dataSchema.methods.incrementPlayCount = function () {
  var inc = 1;
  if (arguments.length) {
    inc = parseInt(arguments[0]);
  }
  this.playCount += inc;
  return this;
};

var hourSchema = new mongoose.Schema({
  hour: Number,
  visited: Number,
  durations: Number,
  playCount: Number
});

module.exports = model.create('VisitedEveryday', {
  biz: String,  // 平台 OTT;IPTV
  date: String,  // 日期
  data: dataSchema,
  hours: [ hourSchema ],
  flavors: [  // 渠道贡献比例
    {
      id: String,  // 渠道id
      name: String,  // 渠道名称
      data: dataSchema,
      hours: [ hourSchema ]
    }
  ],
  products: [
    {
      id: String,
      name: String,  // 产品名称
      data: dataSchema,
      flavors: [  // 渠道贡献比例
        {
          id: String,  // 渠道id
          name: String,  // 渠道名称
          data: dataSchema
        }
      ],
      hours: [ hourSchema ]
    }
  ],
  categories: [
    {
      id: String,
      name: String,  // 栏目名称
      product: String,  // 所属产品id
      data: dataSchema,
      flavors: [  // 渠道贡献比例
        {
          id: String,  // 渠道id
          name: String,  // 渠道名称
          data: dataSchema
        }
      ],
      hours: [ hourSchema ]
    }
  ],
  contents: [
    {
      id: String,
      name: String,  // 内容名称
      product: String,
      category: String,  // 所属栏目id
      doneCount: Number,  // 内容别完整看完的次数
      data: dataSchema,
      flavors: [  // 渠道贡献比例
        {
          id: String,  // 渠道id
          name: String,  // 渠道名称
          data: dataSchema
        }
      ],
      hours: [ hourSchema ]
    }
  ]
}, Manager);